﻿#include "../detail/lang_impl.hh"
#include "service_box.hh"
#include <atomic>
#include <fstream>
#include <mutex>
#include <string>
#include <unordered_map>
#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#else
#include <execinfo.h>
#include <malloc.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif

#include "klogger/interface/logger.h"
#include "../detail/box_config_impl.hh"
#include "../argument/box_argument.hh"
#include "../util/string_util.hh"
#include "../util/os_util.hh"

/**
 * 多服务容器实例，通常情况下只会有一个服务容器实例
 */
std::unordered_map<std::string, kratos::service::ServiceBox *> box_map_;
/**
 * 线程锁，用于保护box_map_
 */
std::mutex map_lock_;

void close_all_box() {
  std::lock_guard<std::mutex> guard(map_lock_);
  for (const auto &it : box_map_) {
    // 设置停止标志
    it.second->set_wait_stop_flag();
  }
}

void reload_config() {
  std::lock_guard<std::mutex> guard(map_lock_);
  for (const auto &it : box_map_) {
    auto &impl =
      dynamic_cast<kratos::config::BoxConfigImpl &>(it.second->get_config());
    const auto &config_file_path = impl.get_config_file_path();
    std::string error;
    if (!impl.reload(config_file_path, error)) {
      // 重新加载失败
      it.second->write_log(
        kratos::lang::LangID::LANG_OS_RELOAD_CONFIG_FAIL,
        klogger::Logger::FAILURE, config_file_path.c_str(),
        error.c_str()
      );
    } else {
      // 重新加载成功
      it.second->write_log(
        kratos::lang::LangID::LANG_OS_RELOAD_CONFIG_SUCCESS,
        klogger::Logger::WARNING, config_file_path.c_str()
      );
    }
  }
}

std::atomic_int proc_ref(0);

bool daemonize(const std::string &name) {
  if (proc_ref > 0) {
    return true;
  }
  // 获取PID文件目录
  std::string fileName = kratos::util::get_binary_path() +
      "/" + name + ".pid";
#ifndef WIN32
  daemon(1, 0);
#endif // WIN32
  // 写入进程PID
  std::ofstream file;
  file.open(fileName, std::ios::out | std::ios::trunc);
  if (file) {
    file << kratos::util::get_pid();
    file.close();
  }
  proc_ref += 1;
  return true;
}

void daemon_finalize(const std::string &name) {
  proc_ref -= 1;
  if (proc_ref > 0) {
    return;
  }
  std::string fileName = kratos::util::get_binary_path() +
      "/" + name + ".pid";
  // 删除PID文件
  remove(fileName.c_str());
}

#ifdef WIN32
// WINDOWS信号处理
static BOOL CtrlHandler(DWORD fdwCtrlType) {
  switch (fdwCtrlType) {
  case CTRL_C_EVENT: {
    // 关闭
    close_all_box();
  } break;
  case CTRL_BREAK_EVENT: {
    // 热加载信号
    reload_config();
  } break;
  default: {
    // 忽略信号
  } break;
  }
  return TRUE;
}
#else
// LINUX信号处理
static void SignalHandler(int s) {
  switch (s) {
  case SIGINT:
  case SIGQUIT:
  case SIGHUP:
  case SIGTERM:
    // 关闭
    close_all_box();
    break;
  case SIGUSR1: // 重新加载配置
    reload_config();
    break;
  case SIGUSR2: // 通知进入维护模式
    // 通知进入维护模式
    break;
  default:
    break;
  }
}
#endif // WIN32

auto install_os_things(const std::string &name,
  kratos::service::ServiceBox *box) -> bool {
  {
    std::lock_guard<std::mutex> guard(map_lock_);
    box_map_[name] = box;
  }
  #ifdef WIN32
    ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
  #else
    signal(SIGINT, SignalHandler);
    signal(SIGQUIT, SignalHandler);
    signal(SIGTERM, SignalHandler);
    signal(SIGHUP, SignalHandler);
    signal(SIGUSR1, SignalHandler);
    signal(SIGUSR2, SignalHandler);
  #endif // WIN32
  return true;
}

auto uninstall_os_things(const std::string &name) -> void {
  std::lock_guard<std::mutex> guard(map_lock_);
  box_map_.erase(name); 
}

auto get_pid_file_path(kratos::service::ServiceBox *box) -> std::string {
  if (!box) {
    return "";
  }
  if (box->get_config().is_start_as_daemon() ||
      box->get_argument().is_daemon()) {
    return kratos::util::get_binary_path() + "/" +
        box->get_config().get_box_name() + ".pid";
  } else {
    return "";
  }
}
